package com.bos.controller;

import com.bos.dao.*;
import com.bos.domain.*;
import com.bos.editor.*;
import com.bos.util.UrlUtil;
import com.bos.util.enums.JenjangSekolah;
import com.bos.util.enums.SatuanPendidikan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.validation.Valid;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: Latief
 * Date: 3/17/11
 * Time: 8:29 PM
 * To change this template use File | Settings | File Templates.
 */
@Controller
public class SekolahController {

    private SekolahDAO sekolahDAO;
    private KabupatenDAO kabupatenDAO;
    private KecamatanDAO kecamatanDAO;
    private BankDAO bankDAO;
    private KelurahanDAO kelurahanDAO;
    private RestTemplate restTemplate;
    /*private Credentials credentials;*/


    /* --------------------- Getter and Setter ---------------------*/

    /*public Credentials getCredentials() {
        return credentials;
    }

    @Autowired
    public void setCredentials(Credentials credentials) {
        this.credentials = credentials;
        if (restTemplate != null) {
            CommonsClientHttpRequestFactory factory = (CommonsClientHttpRequestFactory) restTemplate.getRequestFactory();
            HttpClient client = factory.getHttpClient();
            client.getState().setCredentials(AuthScope.ANY, credentials);
        }
    }*/

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;

//        if (credentials != null) {
//            CommonsClientHttpRequestFactory factory = (CommonsClientHttpRequestFactory) restTemplate.getRequestFactory();
//            HttpClient client = factory.getHttpClient();
//            client.getState().setCredentials(AuthScope.ANY, credentials);
//        }
    }

    @Autowired
    public void setSekolahDAO(SekolahDAO sekolahDAO) {
        this.sekolahDAO = sekolahDAO;
    }

    @Autowired
    public void setBankDAO(BankDAO bankDAO) {
        this.bankDAO = bankDAO;
    }

    @Autowired
    public void setKelurahanDAO(KelurahanDAO kelurahanDAO) {
        this.kelurahanDAO = kelurahanDAO;
    }

    @Autowired
    public void setKabupatenDAO(KabupatenDAO kabupatenDAO) {
        this.kabupatenDAO = kabupatenDAO;
    }

    @Autowired
    public void setKecamatanDAO(KecamatanDAO kecamatanDAO) {
        this.kecamatanDAO = kecamatanDAO;
    }
/* -------------------------- Other Methods -------------------------- */

    @RequestMapping(value = "/sekolah", method = RequestMethod.GET)
    public String index(ModelMap modelMap) {
        modelMap.addAttribute("data", sekolahDAO.getAll());

        return "sekolah/index";
    }

    @RequestMapping(value = "/sekolah/new", method = RequestMethod.GET)
    public String create(ModelMap modelMap) {
        Sekolah sekolah = new Sekolah();
        modelMap.addAttribute("sekolah", sekolah);
        modelMap.addAttribute("bankList", bankDAO.getAll());
        modelMap.addAttribute("kabupatenList", kabupatenDAO.getAll());

        modelMap.addAttribute("jenjangSekolahList", Arrays.asList(JenjangSekolah.values()));
        modelMap.addAttribute("satuanPendidikanList", Arrays.asList(SatuanPendidikan.values()));

        return "sekolah/create";
    }

    @RequestMapping(value = "/sekolah", method = RequestMethod.POST)
    public String save(@Valid @ModelAttribute("sekolah") Sekolah sekolah, BindingResult result, ModelMap modelMap) {

        if (sekolah == null) throw new IllegalArgumentException("A Product is required");
        if (result.hasErrors() || !UrlUtil.isPropHostAvailable() || isSekolahAvailable(sekolah)) {
            modelMap.addAttribute("sekolah", sekolah);
            modelMap.addAttribute("kabupatenList", kabupatenDAO.getAll());
            modelMap.addAttribute("bankList", bankDAO.getAll());

            modelMap.addAttribute("jenjangSekolahList", Arrays.asList(JenjangSekolah.values()));
            modelMap.addAttribute("satuanPendidikanList", Arrays.asList(SatuanPendidikan.values()));

            return "sekolah/create";
        }

        //Simpan ke database lokal
        sekolahDAO.save(sekolah);
        //Siapkan data baru yang akan dikirim ke host propinsi
        String restError = "";
        Sekolah sekolahHttpEntity = new Sekolah();
        sekolahHttpEntity.setNpsn(sekolah.getNpsn());
        sekolahHttpEntity.setNss(sekolah.getNss());
        sekolahHttpEntity.setNama(sekolah.getNama());
        sekolahHttpEntity.setAlamat(sekolah.getAlamat());
        sekolahHttpEntity.setKelurahan(sekolah.getKelurahan());
        sekolahHttpEntity.setSatuanPendidikan(sekolah.getSatuanPendidikan());
        sekolahHttpEntity.setJenjangSekolah(sekolah.getJenjangSekolah());
        sekolahHttpEntity.setBank(sekolah.getBank());
        sekolahHttpEntity.setRekening(sekolah.getRekening());
        sekolahHttpEntity.setPenandatangan1(sekolah.getPenandatangan1());
        sekolahHttpEntity.setPenandatangan2(sekolah.getPenandatangan2());
        HttpEntity<Sekolah> httpEntity = new HttpEntity<Sekolah>(sekolahHttpEntity);

        //Kirim data baru dengan json ke host propinsi.
        String hostUrl = UrlUtil.HOST_PROPINSI_URL + "sekolah.json";
        try {
            ResponseEntity<Map> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.POST, httpEntity, Map.class);
            Map<String, Object> response = responseEntity.getBody();
            if (!(Boolean) response.get("success"))
                restError += hostUrl + "\n";
        } catch (Exception e) {
            e.printStackTrace();
            restError += hostUrl + "\n";
        }
        //atribute jika terjadi error saat melakukan penyimpanan ke database kabupaten.
        if (!restError.isEmpty())
            modelMap.addAttribute("restError", restError.trim());

        return "redirect:/sekolah/" + sekolah.getNpsn();
    }

    @RequestMapping(value = "/sekolah/{npsn}", method = RequestMethod.GET)
    public String show(ModelMap modelMap, @PathVariable("npsn") Sekolah sekolah) {
        modelMap.addAttribute("data", sekolah);
        return "sekolah/show";
    }

    @RequestMapping(value = "/sekolah/{npsn}/delete", method = RequestMethod.GET)
    public String delete(ModelMap modelMap, @PathVariable("npsn") Sekolah sekolah) {
        if (!UrlUtil.isPropHostAvailable()) {
            return "redirect:/sekolah";
        }

        //Siapkan data yang akan dihapus ke host propinsi
        String restError = "";
        HttpEntity<Sekolah> httpEntity = new HttpEntity<Sekolah>(sekolah);

        //Kirim data yang akan dihapus dengan json ke host propinsi.
        String hostUrl = UrlUtil.HOST_PROPINSI_URL + "sekolah/" + sekolah.getNpsn() + "/delete.json";
        try {
            ResponseEntity<Map> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.GET, httpEntity, Map.class);
            Map<String, Object> response = responseEntity.getBody();
            if (!(Boolean) response.get("success"))
                restError += hostUrl + "\n";
        } catch (Exception e) {
            e.printStackTrace();
            restError += hostUrl + "\n";
        }
        //atribute jika terjadi error saat melakukan penghapusan data di tiap host.
        if (!restError.isEmpty())
            modelMap.addAttribute("restError", restError.trim());

        //Hapus data lokal setelahnya.
        sekolahDAO.delete(sekolah);
        return "redirect:/sekolah";
    }


    @RequestMapping(value = "/sekolah/{npsn}/edit", method = RequestMethod.GET)
    public String edit(ModelMap modelMap, @PathVariable("npsn") Sekolah sekolah) {
        modelMap.addAttribute("sekolah", sekolah);
        modelMap.addAttribute("bankList", bankDAO.getAll());
        modelMap.addAttribute("kabupatenList", kabupatenDAO.getAll());
        modelMap.addAttribute("kecamatanList", kecamatanDAO.getByKabupaten(sekolah.getKelurahan().getKecamatan().getKabupaten()));
        modelMap.addAttribute("kelurahanList", kelurahanDAO.getByKecamatan(sekolah.getKelurahan().getKecamatan()));

        modelMap.addAttribute("jenjangSekolahList", Arrays.asList(JenjangSekolah.values()));
        modelMap.addAttribute("satuanPendidikanList", Arrays.asList(SatuanPendidikan.values()));

        return "sekolah/edit";
    }

    @RequestMapping(value = "/sekolah", method = RequestMethod.PUT)
    public String update(@Valid @ModelAttribute("sekolah") Sekolah sekolah, BindingResult result, ModelMap modelMap) {
        if (sekolah == null) throw new IllegalArgumentException("A Product is required");
        if (result.hasErrors() || !UrlUtil.isPropHostAvailable()) {
            modelMap.addAttribute("sekolah", sekolah);
            modelMap.addAttribute("bankList", bankDAO.getAll());
            modelMap.addAttribute("kabupatenList", kabupatenDAO.getAll());
            modelMap.addAttribute("kecamatanList", kecamatanDAO.getByKabupaten(sekolah.getKelurahan().getKecamatan().getKabupaten()));
            modelMap.addAttribute("kelurahanList", kelurahanDAO.getByKecamatan(sekolah.getKelurahan().getKecamatan()));

            modelMap.addAttribute("jenjangSekolahList", Arrays.asList(JenjangSekolah.values()));
            modelMap.addAttribute("satuanPendidikanList", Arrays.asList(SatuanPendidikan.values()));
            return "sekolah/edit";
        }

        //Siapkan data baru yang akan dikirim ke host propinsi
        String restError = "";
        HttpEntity<Sekolah> httpEntity = new HttpEntity<Sekolah>(sekolah);

        //Kirim data baru dengan json ke host propinsi.
        String hostUrl = UrlUtil.HOST_PROPINSI_URL + "sekolah.json";
        try {
            ResponseEntity<Map> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.PUT, httpEntity, Map.class);
            Map<String, Object> response = responseEntity.getBody();
            if (!(Boolean) response.get("success"))
                restError += hostUrl + "\n";
        } catch (Exception e) {
            e.printStackTrace();
            restError += hostUrl + "\n";
        }

        //atribute jika terjadi error saat melakukan penyimpanan ke database kabupaten.
        if (!restError.isEmpty())
            modelMap.addAttribute("restError", restError.trim());

        //simpan ke database lokal setelah semua database di semua host lain dirubah.
        sekolahDAO.merge(sekolah);

        return "redirect:/sekolah/" + sekolah.getNpsn();
    }

    /**
     * Apakah sekolah sudah terdaftar di server propinsi?
     *
     * @param sekolah
     * @return false jika belum terdaftar. true jika sudah.
     */
    private boolean isSekolahAvailable(Sekolah sekolah) {
        //Kirim data baru dengan json ke host propinsi.
        String hostUrl = UrlUtil.HOST_PROPINSI_URL + "sekolah/{npsn}.json";
        Map uriVariable = new HashMap();
        uriVariable.put("npsn", sekolah.getNpsn());
        try {
            ResponseEntity<Sekolah> responseEntity = restTemplate.exchange(hostUrl, HttpMethod.GET, null, Sekolah.class, uriVariable);
            Sekolah response = responseEntity.getBody();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @InitBinder
    protected void initBinder(WebDataBinder binder) throws Exception {
        binder.registerCustomEditor(Bank.class, new BankEditor(bankDAO));
        binder.registerCustomEditor(Kelurahan.class, new KelurahanEditor(kelurahanDAO));
        binder.registerCustomEditor(Kabupaten.class, new KabupatenEditor(kabupatenDAO));
        binder.registerCustomEditor(Kecamatan.class, new KecamatanEditor(kecamatanDAO));
        binder.registerCustomEditor(Sekolah.class, new SekolahEditor(sekolahDAO));
    }
}
